<?php

class ChangeSet {
  var $triples;
  var $subjectOfChange;
  var $before;
  var $before_rdfxml;
  var $after;
  var $after_rdfxml;
  var $createdDate = null;
  var $creatorName = null;
  var $changeReason = null;
  var $has_changes = false;
  var $cs_resource = null;
  var $include_count = 0;
  var $changeset_no = 1;

  function ChangeSet($args='') {
		if(is_array($args)){foreach($args as $k=>$v){$this->$k=$v;}}/* subjectOfChange, after, createdDate, creatorName, changeReason */
    $this->init();
  }

  function init( ) {
    if ( isset( $this->after_rdfxml) || isset( $this->before_rdfxml) ) {
      require_once $_SERVER['DOCUMENT_ROOT']."/lib/arc/ARC_rdfxml_parser.php";
      $parser_args=array(
        "bnode_prefix"=>"genid",
        "base"=>"",
      );
      $parser =new ARC_rdfxml_parser($parser_args);

      if ( isset( $this->after_rdfxml) ) {
        $this->after = $parser->parse_data( $this->after_rdfxml );
      }
      if ( isset( $this->before_rdfxml) ) {
        $this->before = $parser->parse_data( $this->before_rdfxml );
      }
	
    }

    $this->triples = array();

    $this->cs_resource = array( "type" => "bnode", "bnode_id"=>"_:cs".$this->changeset_no);
    if ( substr( $this->subjectOfChange, 0, 2 ) == '_:') {
      $cs_cos = array( 'type'=>'bnode', 'bnode_id'=>$this->subjectOfChange);
    }
    else {
      $cs_cos = array( 'type'=>'uri', 'uri'=>$this->subjectOfChange);
    }
		$this->triples[]=array("s"=>$this->cs_resource, "p"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "o"=>array("type"=>"uri", "uri"=>"http://purl.org/vocab/changeset/schema#ChangeSet") );
		$this->triples[]=array("s"=>$this->cs_resource, "p"=>"http://purl.org/vocab/changeset/schema#subjectOfChange", "o"=>$cs_cos );
    if ($this->createdDate != null) {
      $this->triples[]=array("s"=>$this->cs_resource, "p"=>"http://purl.org/vocab/changeset/schema#createdDate", "o"=>array("type"=>"literal", "val"=>$this->createdDate, "dt"=>'', "lang"=>'', "bnode_id"=>'') );
    }
    if ($this->creatorName != null) {
      $this->triples[]=array("s"=>$this->cs_resource, "p"=>"http://purl.org/vocab/changeset/schema#creatorName", "o"=>array("type"=>"literal", "val"=>$this->creatorName, "dt"=>'', "lang"=>'', "bnode_id"=>'') );
    }
    if ($this->changeReason != null) {
      $this->triples[]=array("s"=>$this->cs_resource, "p"=>"http://purl.org/vocab/changeset/schema#changeReason", "o"=>array("type"=>"literal", "val"=>$this->changeReason, "dt"=>'', "lang"=>'', "bnode_id"=>'') );
    }

    if ( ! isset( $this->before ) ) {
      for($i=0,$i_max=count($this->after);$i<$i_max;$i++) {
        if ( ( $this->after[$i]['s']['type'] == 'uri' && $this->after[$i]['s']['uri'] == $this->subjectOfChange) 
            || ( $this->after[$i]['s']['type'] == 'bnode' && $this->after[$i]['s']['bnode_id'] == $this->subjectOfChange ) 
             ) { 
  
          $after_triple = $this->after[$i];
          $this->include_addition( $after_triple );
        }
      }
    }
    else {
      for($i=0,$i_max=count($this->after);$i<$i_max;$i++) {
        if ( ( $this->after[$i]['s']['type'] == 'uri' && $this->after[$i]['s']['uri'] == $this->subjectOfChange) 
            || ( $this->after[$i]['s']['type'] == 'bnode' && $this->after[$i]['s']['bnode_id'] == $this->subjectOfChange ) 
             ) { 
  
          $after_triple = $this->after[$i];
  
          if ( ! $this->triple_in_list( $after_triple, $this->before)) {
            $this->include_addition( $after_triple );
          }
        }  
      }
    }

    if ( ! isset( $this->after ) ) {
      for($i=0,$i_max=count($this->before);$i<$i_max;$i++) {
        if ( ( $this->before[$i]['s']['type'] == 'uri' && $this->before[$i]['s']['uri'] == $this->subjectOfChange) 
            || ( $this->before[$i]['s']['type'] == 'bnode' && $this->before[$i]['s']['bnode_id'] == $this->subjectOfChange) 
             ) { 
  
          $before_triple = $this->before[$i];
          $this->include_removal( $before_triple );
        }
      }
    }
    else {
      for($i=0,$i_max=count($this->before);$i<$i_max;$i++) {
        if ( ( $this->before[$i]['s']['type'] == 'uri' && $this->before[$i]['s']['uri'] == $this->subjectOfChange) 
            || ( $this->before[$i]['s']['type'] == 'bnode' && $this->before[$i]['s']['bnode_id'] == $this->subjectOfChange) 
             ) { 
  
          $before_triple = $this->before[$i];

          if ( ! $this->triple_in_list( $before_triple, $this->after)) {
            $this->include_removal($before_triple);

          }
        }
      }
    }
  }

  function include_removal( $triple) {
    $this->has_changes = true;
    $this->include_count++;
    $removal = array( "type" => "bnode", "bnode_id"=>"_:rem" . $this->include_count.'_changeset_'.$this->changeset_no);
    $this->triples[]=array("s"=>$this->cs_resource, "p"=>"http://purl.org/vocab/changeset/schema#removal", "o"=>$removal );
    $this->triples[]=array("s"=>$removal, "p"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "o"=>array("type"=>"uri", "uri"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement") );
    $this->triples[]=array("s"=>$removal, "p"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#subject", "o"=>$triple['s'] );
    $this->triples[]=array("s"=>$removal, "p"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate", "o"=>array("type"=>"uri", "uri"=>$triple['p'] ) );
    $this->triples[]=array("s"=>$removal, "p"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#object", "o"=>$triple['o'] );
  }

  function include_addition( $triple) {
    $this->has_changes = true;
    $this->include_count++;
    $addition = array( "type" => "bnode", "bnode_id"=>"_:addition" . $this->include_count.'_changeset_'.$this->changeset_no);
    $this->triples[]=array("s"=>$this->cs_resource, "p"=>"http://purl.org/vocab/changeset/schema#addition", "o"=>$addition );
    $this->triples[]=array("s"=>$addition, "p"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "o"=>array("type"=>"uri", "uri"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#Statement") );
    $this->triples[]=array("s"=>$addition, "p"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#subject", "o"=>$triple['s'] );
    $this->triples[]=array("s"=>$addition, "p"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate", "o"=>array("type"=>"uri", "uri"=>$triple['p'] ) );
    $this->triples[]=array("s"=>$addition, "p"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#object", "o"=>$triple['o'] );
  }


  function has_changes() {
    return $this->has_changes;
  }

  function get_triples() {
    return $this->triples;
  }

  function wrap_rdfxml($content) {
		$rdfxml = '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cs="http://purl.org/vocab/changeset/schema#">';
		    $rdfxml .= "\n".$content;
		  $rdfxml .= '</rdf:RDF>';
	    return $rdfxml;    
	}

  function to_rdfxml($wrap_as_document=true) {
	$rdfxml ='';
    $subjectIndex = array();
    for($i=0,$i_max=count($this->triples);$i<$i_max;$i++) {
			$s_val=($this->triples[$i]['s']['type']=="uri")? $this->triples[$i]['s']["uri"] : $this->triples[$i]['s']["bnode_id"];
      if ( ! array_key_exists( $s_val, $subjectIndex ) ) {
        $subjectIndex[$s_val] = array();
      }
      
      array_push( $subjectIndex[$s_val] , $this->triples[$i] );
    }

    foreach ( $subjectIndex as $subject=>$triples) {

      $rdfxml .= '  <rdf:Description';
      if ( $triples[0]['s']['type'] == 'uri' ) {
        $rdfxml .= ' rdf:about="' . $triples[0]['s']['uri'] . '">';
      }
      else {
        $rdfxml .= ' rdf:nodeID="' . substr( $triples[0]['s']['bnode_id'], 2) . '">';
      }
      $rdfxml .= "\n";

      for ($i = 0; $i < count($triples); $i++) {      

        if ( substr( $triples[$i]['p'], 0, strlen( 'http://purl.org/vocab/changeset/schema#') ) == 'http://purl.org/vocab/changeset/schema#') {
          $rdfxml .= '    <cs:' . substr( $triples[$i]['p'], strlen( 'http://purl.org/vocab/changeset/schema#') );
          if ( $triples[$i]['o']['type'] == 'uri' ) {
            $rdfxml .= ' rdf:resource="' . htmlspecialchars($triples[$i]['o']['uri']) . '" />' . "\n";
          }
          elseif ( $triples[$i]['o']['type'] == 'literal' ) {
            if ( isset( $triples[$i]['o']['lang'] ) && $triples[$i]['o']['lang'] != '' ) {
              $rdfxml .= ' xml:lang="' . htmlspecialchars($triples[$i]['o']['lang']) . '"';
            }
      
            $rdfxml .= '>';
            $rdfxml .= htmlspecialchars($triples[$i]['o']['val'], ENT_NOQUOTES, 'UTF-8' );
            $rdfxml .= '</cs:' . substr( $triples[$i]['p'], strlen( 'http://purl.org/vocab/changeset/schema#') ) . ">\n";
          }
          elseif ( $triples[$i]['o']['type'] == 'bnode' ) {
            $rdfxml .= ' rdf:nodeID="' . substr( $triples[$i]['o']['bnode_id'], 2) . '" />' . "\n";
          }
        }
        elseif ( substr( $triples[$i]['p'], 0, strlen( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#') ) == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#') {
          $rdfxml .= '    <rdf:' . substr( $triples[$i]['p'], strlen( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#') );
          if ( $triples[$i]['o']['type'] == 'uri' ) {
            $rdfxml .= ' rdf:resource="' . htmlspecialchars($triples[$i]['o']['uri']) . '" />' . "\n";
          }
          elseif ( $triples[$i]['o']['type'] == 'literal' ) {
            if ( isset( $triples[$i]['o']['lang'] ) && $triples[$i]['o']['lang'] != '' ) {
              $rdfxml .= ' xml:lang="' . htmlspecialchars($triples[$i]['o']['lang']) . '"';
            }
      
            $rdfxml .= '>';
            $rdfxml .= htmlspecialchars($triples[$i]['o']['val'], ENT_NOQUOTES, 'UTF-8' );
            $rdfxml .= '</rdf:' . substr( $triples[$i]['p'], strlen( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#') ) . ">\n";
          }
          elseif ( $triples[$i]['o']['type'] == 'bnode' ) {
            $rdfxml .= ' rdf:nodeID="' . substr( $triples[$i]['o']['bnode_id'], 2) . '" />' . "\n";
          }
        }
      }
      $rdfxml .= '  </rdf:Description>' . "\n";
    }
  if($wrap_as_document) return $this->wrap_rdfxml($rdfxml);
  else return $rdfxml;
  }

  function triple_in_list( $triple, $list ) {
    foreach ($list as $candidate) {
      if ( $triple['s']['type'] == $candidate['s']['type'] && $triple['o']['type'] == $candidate['o']['type'] && $triple['p'] == $candidate['p'] ) {
        if ( ( $triple['s']['type'] == 'uri' && $triple['s']['uri'] == $candidate['s']['uri'] ) || ( $triple['s']['type'] == 'bnode' && $triple['s']['bnode_id'] == $candidate['s']['bnode_id'] ) ) {
          if ( ( $triple['o']['type'] == 'uri' && $triple['o']['uri'] == $candidate['o']['uri'] ) || ( $triple['o']['type'] == 'bnode' && $triple['o']['bnode_id'] == $candidate['o']['bnode_id'] )  || ($triple['o']['type'] == 'literal' && $triple['o']['val'] == $candidate['o']['val']  ) )  {

            if ( $triple['o']['type'] == 'literal' ) {
              if ( array_key_exists('lang', $triple['o']) && array_key_exists('lang', $candidate['o']) && ($triple['o']['lang'] == $candidate['o']['lang'])) {
              return true;
              }
              elseif (! array_key_exists('lang', $triple['o']) && ! array_key_exists('lang', $candidate['o']) ) {
                return true;
              }
              elseif ( array_key_exists('lang', $triple['o']) && ! array_key_exists('lang', $candidate['o']) && ! isset($triple['lang'] ) ) {
                return true;
              }
              elseif ( ! array_key_exists('lang', $triple['o']) && array_key_exists('lang', $candidate['o']) && ! isset($candidate['lang']) ) {
                return true;
              }
            }
            else {
              return true;
            }
          } 
        }
      } 
    }

    return false;
  }


}

/*****************************************************************************
*****************************************************************************/
class ChangeSetBatch {
  var $changesets;
  var $after;
  var $after_rdfxml;
  var $before;
  var $before_rdfxml;
  var $createdDate = null;
  var $creatorName = null;
  var $changeReason = null;
  var $sparqlService;

  /* args can be after, createdDate, creatorName, changeReason */
  function ChangeSetBatch($args='') {
		if(is_array($args)){foreach($args as $k=>$v){$this->$k=$v;}}
    $this->init();
  }

  function init( ) {
    if ( isset( $this->after_rdfxml) ) {
      require_once $_SERVER['DOCUMENT_ROOT']."/lib/arc/ARC_rdfxml_parser.php";
      $parser_args=array(
        "bnode_prefix"=>"genid",
        "base"=>""
      );
      $parser =new ARC_rdfxml_parser($parser_args);
      $this->after = $parser->parse_data( $this->after_rdfxml );
    }


    $this->changesets = array();

    $subjectIndex = array();

    for($i=0,$i_max=count($this->after);$i<$i_max;$i++) {
      if ( $this->after[$i]['s']['type'] == 'uri' ) {
        if ( ! array_key_exists( $this->after[$i]['s']['uri'], $subjectIndex ) ) {
          $subjectIndex[ $this->after[$i]['s']['uri'] ] = $this->after[$i]['s']['uri'];
        }
      }
      else {
        if ( ! array_key_exists( $this->after[$i]['s']['bnode_id'], $subjectIndex ) ) {
          $subjectIndex[ $this->after[$i]['s']['bnode_id'] ] = $this->after[$i]['s']['bnode_id'];
        }
      }
    }

    if ( isset ($this->before) ) {
      $beforeSubjects = array();
      for($i=0,$i_max=count($this->before);$i<$i_max;$i++) {
        if ( $this->before[$i]['s']['type'] == 'uri' ) {
          if ( ! array_key_exists( $this->before[$i]['s']['uri'], $beforeSubjects ) ) {
            $beforeSubjects[ $this->before[$i]['s']['uri'] ] = array();
          }
          array_push( $beforeSubjects[ $this->before[$i]['s']['uri'] ], $this->before[$i]);
  
        }
        else {
          if ( ! array_key_exists( $this->before[$i]['s']['bnode_id'], $beforeSubjects ) ) {
            $beforeSubjects[ $this->before[$i]['s']['bnode_id'] ] = array();
          }
          array_push( $beforeSubjects[ $this->before[$i]['s']['bnode_id']  ], $this->before[$i]);
        }
      }
    }

    $subjects = array_keys( $subjectIndex );
    
    for($i=0,$i_max=count($subjects);$i<$i_max;$i++) {
      if ( isset ($this->before) && array_key_exists( $subjects[$i], $beforeSubjects ) ) {
          $this->changesets[] = new ChangeSet( array( 'subjectOfChange'=>$subjects[$i], 'after'=>$this->after
                                                                            , 'before'=>$beforeSubjects[ $subjects[$i] ]
                                                                            , 'createdDate'=>$this->createdDate
                                                                            , 'creatorName'=>$this->creatorName
                                                                            , 'changeReason'=>$this->changeReason
                                                                             ) );

      }
      else {
        if ( substr($subjects[$i], 0, 2) != '_:' && isset( $this->sparqlService ) ) {
          $describe_response = $this->sparqlService->describe( $subjects[$i] );
          $before_rdfxml = $describe_response->body;
          // echo "Content-type: text/plain\r\n\r\n";
          // echo $before_rdfxml;
  
          $this->changesets[] = new ChangeSet( array( 'subjectOfChange'=>$subjects[$i], 'after'=>$this->after
                                                                            , 'before_rdfxml'=>$before_rdfxml
                                                                            , 'createdDate'=>$this->createdDate
                                                                            , 'creatorName'=>$this->creatorName
                                                                            , 'changeReason'=>$this->changeReason
                                                                             ) );
        }
        else {
          $this->changesets[] = new ChangeSet( array( 'subjectOfChange'=>$subjects[$i], 'after'=>$this->after
                                                                            , 'createdDate'=>$this->createdDate
                                                                            , 'creatorName'=>$this->creatorName
                                                                            , 'changeReason'=>$this->changeReason											,
'changeset_no'=>$i															,

                                                                             ) );
        }
      }
    }


  }

  function get_changesets() {
    return $this->changesets;
  }




}


?>